package com.yanfan.ccapicode.mangaer.impl;

import cn.hutool.core.collection.CollectionUtil;
import com.alibaba.fastjson2.JSONObject;
import com.yanfan.ccapicode.bean.dto.DeviceFunctionDTO;
import com.yanfan.ccapicode.bean.info.ActionContext;
import com.yanfan.ccapicode.bean.info.DeviceInfo;
import com.yanfan.ccapicode.constant.SdkConstants;
import com.yanfan.ccapicode.dao.DeviceRepository;
import com.yanfan.ccapicode.dao.UserAuthorizeRepository;
import com.yanfan.ccapicode.dao.entity.DeviceDO;
import com.yanfan.ccapicode.dao.entity.UserAuthorizeDO;
import com.yanfan.ccapicode.enums.ThirdPartyCloudEnum;
import com.yanfan.ccapicode.exception.ResultCode;
import com.yanfan.ccapicode.exception.ServiceException;
import com.yanfan.ccapicode.mangaer.DeviceServiceHttpManager;
import com.yanfan.ccapicode.util.CollectionFunctionUtils;
import com.yanfan.ccapicode.util.TestUtil;
import com.yanfan.common.core.mq.MQSendMessageBo;
import com.yanfan.common.core.mq.message.FunctionCallBackBo;
import com.yanfan.common.enums.TopicType;
import com.yanfan.common.utils.StringUtils;
import com.yanfan.common.utils.gateway.mq.TopicsUtils;
import com.yanfan.iot.cache.ITSLCache;
import com.yanfan.iot.domain.Device;
import com.yanfan.iot.service.IDeviceService;
import com.yanfan.mqtt.manager.MqttRemoteManager;
import com.yanfan.mqtt.model.PushMessageBo;
import com.yanfan.protocol.base.protocol.IProtocol;
import com.yanfan.protocol.service.IProtocolManagerService;
import lombok.RequiredArgsConstructor;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpMethod;
import org.springframework.http.ResponseEntity;
import org.springframework.lang.Nullable;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;

import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;

/**
 * :)
 * 实际解除设备方法
 */
@Service
@RequiredArgsConstructor
public class DeviceServiceHttpManagerImpl implements DeviceServiceHttpManager {

    private final Logger logger = LoggerFactory.getLogger(DeviceServiceHttpManager.class);
    private final RestTemplate restTemplate;
    private final DeviceRepository deviceRepositoryImpl;
    private final UserAuthorizeRepository userAuthorizeRepository;
    private final ITSLCache itslCache;
    private final MqttRemoteManager remoteManager;
    private final IProtocolManagerService protocolManagerService;
    private final IDeviceService deviceService;
    private final TopicsUtils topicsUtils;


    /**
     * @param context
     * @return
     */
    @Override
    public List<DeviceInfo> getDeviceListByUserId(ActionContext context) {
        logger.debug("{}平台：发现设备.请求路由：{}，通过用户id：{}，业务id：{}", context.getThirdPartyCloudConfigInfo().getThirdPartyCloud(), context.getThirdPartyCloudConfigInfo().getMainUrl() + SdkConstants.DISCOVER_INTERFACE, context.getAccessTokenInfo().getUser().getUserId(), context.getAccessTokenInfo().getBusinessId());
        ThirdPartyCloudEnum partyCloud = context.getThirdPartyCloudConfigInfo().getThirdPartyCloud();
        String userId = context.getAccessTokenInfo().getUser().getUserId();
        UserAuthorizeDO userAuthorizeDO = userAuthorizeRepository.selectByUserIdAndThirdPartyCloud(userId, partyCloud);
        DeviceDO deviceDO = new DeviceDO();
        deviceDO.setUserId(userAuthorizeDO.getSysUserId());
        List<DeviceDO> devices = deviceRepositoryImpl.selectCcapiDeviceList(deviceDO);
//        return new ArrayList<>(TestUtil.getTestDevice()); // 测试数据
        return devices.stream().map(device -> DeviceInfo.builder()
                .productId(String.valueOf(device.getProductId()))
                .deviceId(device.getDeviceId())
                .serialNumber(device.getSerialNumber())
                .deviceName(device.getDeviceName())
                .modelName(device.getProductName())
                .groupName(device.getGroupName())
                .version(String.valueOf(device.getFirmwareVersion()))
                .online(device.getStatus() == 3)
                // TODO lsy 在这里设置所有的点位
                .deviceFunctions(
                        itslCache.getThingsModelList(Long.valueOf(device.getProductId()))
                                .stream()
                                .filter(item -> Objects.equals(item.getType(), 2))
                                .map(item -> DeviceFunctionDTO.builder()
                                        .signCode(item.getId())
                                        .deviceId(device.getDeviceId())
                                        .value(item.getValue())
                                        .build())
                                .collect(Collectors.toList())
                )
                .build()).collect(Collectors.toList());
    }

    @Override
    public DeviceInfo getDeviceStatusByDeviceId(ActionContext context, String deviceId) {
        logger.debug("{}平台：查询设备状态.请求路由：{}，通过设备id：{}，业务id：{}", context.getThirdPartyCloudConfigInfo().getThirdPartyCloud(), context.getThirdPartyCloudConfigInfo().getMainUrl() + SdkConstants.QUERY_INTERFACE, deviceId, context.getAccessTokenInfo().getBusinessId());
        return this.getDevicesStatusByDeviceIds(context, CollectionUtil.newArrayList(deviceId)).get(2);
    }

    @Override
    public List<DeviceInfo> getDevicesStatusByDeviceIds(ActionContext context, List<String> deviceIds) {
        logger.debug("{}平台：批量查询设备状态.请求路由：{}，通过设备ids：{}，业务id：{}", context.getThirdPartyCloudConfigInfo().getThirdPartyCloud(), context.getThirdPartyCloudConfigInfo().getMainUrl() + SdkConstants.QUERY_INTERFACE, CollectionUtil.join(deviceIds, ","), context.getAccessTokenInfo().getBusinessId());
        return new ArrayList<>(TestUtil.getTestDevice());
    }

    @Override
    public DeviceInfo command(ActionContext context, DeviceFunctionDTO deviceCommand) {
        logger.debug("{}平台：控制设备.请求路由：{}，通过设备id：{}， 控制命令为：{}，业务id：{}", context.getThirdPartyCloudConfigInfo().getThirdPartyCloud(), deviceCommand.getDeviceId(), context.getThirdPartyCloudConfigInfo().getMainUrl() + SdkConstants.CONTROL_INTERFACE, deviceCommand.getSignCode(), context.getAccessTokenInfo().getBusinessId());
        return CollectionUtil.getFirst(this.commands(context, CollectionUtil.newArrayList(deviceCommand)));
    }

    /**
     * FIXME 调试返回参，最佳体验是控制什么就返回什么
     *
     * @param deviceCommands
     */
    @Override
    public List<DeviceInfo> commands(ActionContext context, List<DeviceFunctionDTO> deviceCommands) {
        logger.debug("{}平台：批量控制设备.请求路由：{}，信息为：{}，业务id：{}", context.getThirdPartyCloudConfigInfo().getThirdPartyCloud(), context.getThirdPartyCloudConfigInfo().getMainUrl() + SdkConstants.CONTROL_INTERFACE, CollectionUtil.join(deviceCommands, ","), context.getAccessTokenInfo().getBusinessId());
        try {
            DeviceFunctionDTO functionDTO = deviceCommands.get(0);
            String serialNumber = functionDTO.getSerialNumber();
            // 查询设备
            Device device = deviceService.selectDeviceBySerialNumber(serialNumber);
            // 查询产品对应的协议
            IProtocol protocol = protocolManagerService.getProtocolByProtocolCode(device.getProtocolCode());

            //组装协议中encode编码方法入口对象
            MQSendMessageBo mqSendMessageBo = new MQSendMessageBo();
            mqSendMessageBo.setSerialNumber(device.getSerialNumber());
            JSONObject jsonObject = new JSONObject();
            for (DeviceFunctionDTO command : deviceCommands) {
                jsonObject.put(command.getSignCode(), command.getValue());
            }
            mqSendMessageBo.setParams(jsonObject);
            FunctionCallBackBo encode = protocol.encode(mqSendMessageBo);
            byte[] encodeMessage = encode.getMessage();
            String  message1 = new String(encodeMessage, StandardCharsets.UTF_8);
            if (StringUtils.isEmpty(message1)) {
                logger.error("匹配协议编码失败，请检查协议编码是否正确");
            } else {
                // 发送至前端
                PushMessageBo messageBo = new PushMessageBo();
                messageBo.setTopic(topicsUtils.buildTopic(device.getProductId(), serialNumber, TopicType.FUNCTION_GET));
                messageBo.setMessage(message1);
                remoteManager.pushCommon(messageBo);
            }
        } catch (Exception e) {
            logger.error("匹配协议编码失败，" + e.getMessage());
        }

        Map<String, List<DeviceFunctionDTO>> deviceMap = CollectionFunctionUtils.groupTo(deviceCommands, DeviceFunctionDTO::getDeviceId);
        // return new ArrayList<>(TestUtil.getControlTest(deviceCommands));
        return deviceMap.keySet().stream().map(deviceId -> {
            List<DeviceFunctionDTO> deviceFunctionDTOS = deviceMap.get(deviceId);
            return DeviceInfo.builder()
                    .productId(deviceFunctionDTOS.get(0).getProductId())
                    .deviceId(deviceId)
                    .online(true)
                    .deviceFunctions(
                            deviceFunctionDTOS.stream().map(dc -> DeviceFunctionDTO.builder()
                                    .signCode(dc.getSignCode())
                                    .deviceId(dc.getDeviceId())
                                    .value(dc.getValue())
                                    .build()).collect(Collectors.toList()))
                    .build();
        }).collect(Collectors.toList());
    }

    private <T> T request(String url, HttpMethod method,
                          @Nullable HttpEntity<?> requestEntity, Class<T> responseType, Map<String, ?> uriVariables) {
        ResponseEntity<String> response = restTemplate.exchange(url, method, requestEntity, String.class, uriVariables);
        if (!response.getStatusCode().is2xxSuccessful()) {
            throw new ServiceException(ResultCode.ERROR);
        }
        String commonResult = response.getBody();
        Objects.requireNonNull(commonResult, "body can't be null");
        return (T) JSONObject.parseObject(JSONObject.toJSONString(commonResult), responseType);
    }

}
